package com.heima.media.service.Impl;

import com.alibaba.fastjson.JSON;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleFeign;
import com.heima.media.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class AuditServiceImpl implements IAuditService {

    @Autowired
    @Lazy  //懒加载  解决循环依赖问题
    private IWmNewsService wmNewsService;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private MinIOService minIOService;
    @Autowired
    private ArticleFeign articleFeign;
    @Autowired
    private IWmUserService wmUserService;
    @Autowired
    private IWmChannelService wmChannelService;

    @Override
    @Async  //异步请求  原理：多线程
    public void audit(WmNews wmNews) {

        boolean isPass = true;
        // 自管理敏感词的审核
        isPass =checkSensitive(wmNews);
        if (!isPass)return;


        //        阿里云文本审核
        isPass =checkText(wmNews);
        if (!isPass)return;
        //        阿里云图片审核
        isPass =checkImage(wmNews);
        if (!isPass)return;
        // 审核通过 feign远程调用  保存apArticle

//        判断现在的时间是不是已经到达了发布时间
         // 如果当前时间>发布时间，就意味着已经到达发布时间
        if (System.currentTimeMillis() >= wmNews.getPublishTime().getTime()){
            // feign远程调用  保存apArticle
            Long article = saveApArticle(wmNews);
            wmNews.setArticleId(article);
            wmNews.setStatus(9);
            wmNewsService.updateById(wmNews);
        }else {
            // 只修改一下状态
            wmNews.setStatus(8);
            wmNewsService.updateById(wmNews);

            //使用Redisson做延迟任务
            RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque("news-dqueue");
            // 根据blockingDeque获取延迟队列
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
            // 放数据
            // 即将发布的时间-当前时间
            long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
            delayedQueue.offer(wmNews.getId(),time, TimeUnit.MILLISECONDS);
            log.error("延迟消息发送成功，预计在"+time+"毫秒后，会执行某一个方法"+new Date());

        }
    }

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IWmSensitiveService wmSensitiveService;
//    在文章审核的代码中添加自管理敏感词审核
    private boolean checkSensitive(WmNews wmNews) {
        // 1.初始化DFA算法的大Map
        List<WmSensitive> wmSensitiveList = wmSensitiveService.list();

//        List<String> list = wmSensitiveList.stream().map(s -> s.getSensitives()).collect(Collectors.toList());
        List<String> stringList = new ArrayList<>();
        for (WmSensitive sensitive : wmSensitiveList) {
            stringList.add(sensitive.getSensitives());
        }
        SensitiveWordUtil.initMap(stringList);
        // 2.检查文章文本中是否包含敏感词
//        text变量中放的是自媒体文章标题和文章内容
        String text = wmNews.getTitle();
        String content = wmNews.getContent();
        //从文章内容中获取所有图片，构建到一个list集合中
        List<ContentDto> contentDtos= JSON.parseArray(content,ContentDto.class);
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("text")){
                text += contentDto.getValue();
            }
        }

        Map<String, Integer> matchWordsMap = SensitiveWordUtil.matchWords(text);
        if (matchWordsMap.size() == 0) {
            return true; //审核通过
        }else {
            wmNews.setStatus(2);
            //        stringIntegerMap = {小额贷款=1, 随机随贷=1, 无抵押=2}
            Set<String> strings = matchWordsMap.keySet();
            String reason = String.join(",", strings);
            wmNews.setReason("自管理敏感词审核不通过，原因是内容中包含：" + reason);
            wmNewsService.updateById(wmNews);
            return false;  //驳回审核
        }

    }

    // 测试
    @Override
    public void audit(Integer newsId) {
        WmNews wmNews = wmNewsService.getById(newsId);
        audit(wmNews);
    }

    //    远程发布app文章，  根据wmNews 构建ArticleDto
    public Long saveApArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        dto.setContent(wmNews.getContent());
//        dto.setId();
        dto.setTitle(wmNews.getTitle());
        // 自媒体用户中是有app文章作者
        // 根据当前自媒体人的ID查询自媒体人对象
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());  //app文章作者id
        dto.setAuthorName(wmUser.getName());
        dto.setChannelId(wmNews.getChannelId());
        WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);//文章标记     0 普通文章   1 热点文章     2置顶文章      3 精品文章       4 大V 文章

        String images = wmNews.getImages();
        List<ImageDto> imageDtoList = JSON.parseArray(images, ImageDto.class);
        List<String> urlList = new ArrayList<>();
        for (ImageDto imageDto : imageDtoList) {
            urlList.add(imageDto.getUrl());
        }
        dto.setImages(String.join(",",urlList));
        dto.setLabels(wmNews.getLabels());
        dto.setPublishTime(wmNews.getPublishTime());
        return articleFeign.saveArticle(dto).getData();

    }

    private boolean checkImage(WmNews wmNews) {
        //        图片包括：文章内容图片+文章的封面图片
        //文章封面图片
        List<ImageDto> imageDtoList = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        String content = wmNews.getContent();
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("image")) {
                ImageDto imageDto = new ImageDto();
                imageDto.setId(contentDto.getId());
                imageDto.setUrl(contentDto.getValue());

                if (!imageDtoList.contains(imageDto)) {
                    imageDtoList.add(imageDto);
                }
            }
        }
        // 现在的imageDtoList就是封面图片+内容图片
        try {
            List<byte[]> imageList = new ArrayList<>();
            // 图片的下载，下载后上传到阿里云审核
            for (ImageDto imageDto : imageDtoList) {
                InputStream inputStream = minIOService.download(imageDto.getUrl());
                byte[] bytes = IOUtils.toByteArray(inputStream);  //IOUtils-->Apache的
                imageList.add(bytes);
            }
                //        把图片都转成字节数组
                Map map = greenImageScan.imageScan(imageList);    // List<byte[]> imageList
                String suggestion = (String) map.get("suggestion");
                //            pass：文本正常，可以直接放行。
//            review：文本需要进一步人工审核。             label=porn
//            block：文本违规，可以直接删除或者限制公开。  label=porn
                switch (suggestion){
                    case "pass":{
                        return true;
                    }
                    case "review":{
                        // 修改自媒体文章的状态和原因
                        wmNews.setStatus(3);
                        String label = (String) map.get("label");
                        wmNews.setReason("阿里云图片审核需要人工介入，原因是：" + label);
                        wmNewsService.updateById(wmNews);
                        return false;
                    }
                    case "block":{
                        // 修改自媒体文章的状态和原因
                        wmNews.setStatus(2);
                        String label = (String) map.get("label");
                        wmNews.setReason("阿里云图片审核不通过，原因是：" + label);
                        wmNewsService.updateById(wmNews);
                        return false;
                    }
                }
            } catch(Exception e){
                e.printStackTrace();
            }
            return false;
        }

    private boolean checkText(WmNews wmNews) {
        //        审核文本包括：文章标题+文章的内容
        String text = wmNews.getTitle();
        String content = wmNews.getContent();
        //从文章内容中获取所有图片，构建到一个list集合中
        List<ContentDto> contentDtos= JSON.parseArray(content,ContentDto.class);
        for (ContentDto contentDto : contentDtos) {
            if (contentDto.getType().equals("text")){
                text += contentDto.getValue();
            }
        }
        try {
            Map map = greenTextScan.greenTextScan(text);
            String suggestion = (String) map.get("suggestion");
            //            pass：文本正常，可以直接放行。
//            review：文本需要进一步人工审核。             label=porn
//            block：文本违规，可以直接删除或者限制公开。  label=porn
            switch (suggestion){
                case "pass":{
                    return true;
                }
                case "review":{
                    // 修改自媒体文章的状态和原因
                    wmNews.setStatus(3);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核需要人工介入，原因是："+label);
                    wmNewsService.updateById(wmNews);
                    return false;
                }
                case "block":{
                    // 修改自媒体文章的状态和原因
                    wmNews.setStatus(2);
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核不通过，原因是："+label);
                    wmNewsService.updateById(wmNews);
                    return false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
